node学习笔记——初识Mongoose

Mongoose 是一个将JavaScript对象与数据库产生关系的一个框架,object related model。操作对象,就是操作数据库了;对象产生了,同时也持久化了。

这个思路是Java三大框架SSH中Hibernate框架的思路。彻底改变了人们使用数据库的方式。官网

官网上的 hello world 栗子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//引包,并不需要引用mongodb这个包
var mongoose = require('mongoose');
//链接数据库,haha是数据库名字
mongoose.connect('mongodb://localhost/haha');

//创建了一个模型。猫的模型。所有的猫,都有名字,是字符串。“类”。
var Cat = mongoose.model('Cat', { name: String });
//实例化一只猫
var kitty = new Cat({ name: 'Zildjian' });
//调用这只猫的save方法,保存这只猫
kitty.save(function (err) {
console.log('喵喵喵');
});

var tom = new Cat({"name":"汤姆"});
tom.save(function(){
console.log('喵喵喵');
});

上面的代码中,没有一个语句是明显的操作数据库,感觉都在创建类、实例化类、调用类的方法。都在操作对象,但是数据库同步被持久了。

mongoose的哲学,就是让你用操作对象的方式操作数据库。

创建一个模型:

1
mongoose.model("Cat",{"name" : String , "age" : Integer});

就可以被实例化:

1
var kitty = new Cat({ name: 'Zildjian' });

然后这个实例就可以被 save:

1
2
3
kitty.save(function (err) {
console.log('喵喵喵');
});

你需要牢记的就是:使用 mongoose 进行的所有操作都不是对数据库进行的,都是对类、实例进行的。但是数据库的持久化自动完成了。

Schema 之所以能够定义documents, 是因为他可以限制你输入的字段及其类型. mongoose支持的基本类型有:

  • String
  • Number
  • Date
  • Buffer
  • Boolean
  • Mixed
  • ObjectId
  • Array

数据库连接方式

连接数据库并获取数据库对象 db 的两种方式:

1
2
3
4
5
6
7
8
9
10
11
12
const mongoose = require('mongoose');
//创建数据库连接
mongoose.connect('mongodb://localhost:27017/haha');
const db = mongoose.connection;
//监听open事件
db.once('open',()=>{
console.log("数据库成功连接");
});
// 连接接错误
db.on('error', function(error) {
console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11
var mongoose = require('mongoose');
//创建数据库连接
var db = mongoose.createConnection('mongodb://127.0.0.1:27017/haha');
//监听open事件
db.once('open', function (callback) {
console.log("数据库成功连接");
});
// 连接接错误
db.on('error', function(error) {
console.log(error);
});

mongoose.createConnection() 和 mongoose.connect() 区别:

首先,我们需要定义一个连接,如果你的app只用到一个数据库,你应该使用 mongoose.connect。如果你还需要连接其他数据库,使用 mongoose.createConnection。

所有的 connect and createConnection 使用 mongodb:// URI, or the parameters host, database, port, options.等参数

一旦连接,Connection对象会触发open事件,如果你使用 mongoose.connect, Connection 对象就是默认的 mongoose.connection,而使用 mongoose.createConnection 返回值就是 Connection.

注意:Mongoose会缓存所有命令直到连接上数据库,这意味着你不必等待它连接MongoDB再定义 models,执行 queries 等。

定义模型 schema

创造schema → 定义一些schema的静态方法 → 创造模型

创造schema用什么语句? new mongoose.schema({});

创造模型用什么语句? db.model(“Student”,schema名字);

例如一个学生类的创建与使用:

模型类 Student.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var mongoose = require('mongoose');
var db = require("./db.js");

//创建了一个schema结构。
var studentSchema = new mongoose.Schema({
name : {type : String},
age : {type : Number},
sex : {type : String}
});
//创建静态方法
studentSchema.statics.zhaoren = function(name, callback) {
this.model('Student').find({name: name}, callback);
};
//创建修改的静态方法
studentSchema.statics.xiugai = function(conditions,update,options,callback){
this.model("Student").update(conditions, update, options, callback);
}
//创建了一个模型,就是学生模型,就是学生类。
//类是基于schema创建的。
var studentModel = db.model('Student', studentSchema);
//向外暴露
module.exports = studentModel;

在这里, mongoose.model里面定义的第一个参数,比如’Student’, 并不是数据库中的, collection. 他只是collection的单数形式, 实际上在db中的collection是’Students’.

想两边名称保持一致,可参考 Mongoose在创建Model时对Collection的命名策略

创建连接数据库 db.js

1
2
3
4
5
6
7
8
9
10
//引包
var mongoose = require('mongoose');
//创建数据库连接
var db = mongoose.createConnection('mongodb://127.0.0.1:27017/haha');
//监听open事件
db.once('open', function (callback) {
console.log("数据库成功连接");
});
//向外暴露这个db对象
module.exports = db;

使用程序 app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//定义了一个模型,学生模型,“学生类”
var Student = require("./models/Student.js");

//实例化了一个学生类,这里用于测试创建一条学生数据
//var xiaoming = new Student({"name":"小明","age":12,"sex":"男"});
////保存这个学生类
//xiaoming.save(function(){
// console.log("存储成功");
//});


//用类来创建一个对象(工厂)
Student.create({"name":"小红","age":13,"sex":"女"},function(error){
console.log("保存成功");
})
//使用静态方法
Student.zhaoren("小明",function(err,result){
console.log(result);
});

Student.xiugai({"name":"小明"},{$set : {"age":30}},{},function(){
console.log("改年龄成功");
});

SchemaType

ype属性指定SchemaType类型,不同的SchemaType类型还有其他不同的属性配置:

1
2
3
4
5
6
var schema2 = new Schema({
test: {
type: String,
lowercase: true // 总是将'test'转换为小写
}
});

公有的类型有:

  • required: 必选验证器。
  • default: 默认值。Any或function,如果该值是一个函数,则该函数的返回值将用作默认值。
  • select: boolean值, 指定是否被投影
  • validate: 验证器
  • get: get方法,using Object.defineProperty()
  • set: set方法 using Object.defineProperty()
  • alias: 别名

其他公有类型

设置索引

这里设置索引分两种,一种设在Schema filed, 另外一种设在 Schema.index 里:

在 field 设置:

1
2
3
4
5
var testSchema = new Schema({
name: String,
type: String,
tags: { type: [String], index: true }
});

在Schema.index中设置:

1
2
//1 表示正序, -1 表示逆序
testSchema.index({ name: 1, type: -1 });

两者效果是一样的,不过推荐直接在Schema level中设置, 这样分开能够增加可读性。

当应用启动的时候, Mongoose 会自动为 Schema 中每个定义了索引的调用 ensureIndex,确保生成索引,并在所有的 secureIndex 调用成功或出现错误时,在 Model 上发出一个’index’事件。 开发环境用这个很好, 但是建议在生产环境不要使用这个,因为这样可能严重拖慢查询或者创建速度,所以一般而言,我们需要将该option 关闭.使用下面的方法禁用 ensureIndex:

1
2
3
4
5
6
7
mongoose.connect('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } });  //真心推荐
// or
mongoose.createConnection('mongodb://user:pass@localhost:port/database', { config: { autoIndex: false } }); //不推荐
// or
animalSchema.set('autoIndex', false); //推荐
// or
new Schema({..}, { autoIndex: false }); //懒癌不推荐

Schema.statics与Schema.methods

Model的静态方法,即可以在 Model 上调用 相关的查询或者删除:

1
2
3
4
5
6
7
8
9
10
// 给model添加一个find方法
testSchema.statics.find = function (name, cb) {
//这里的this 指的就是Model
return this.find({ name: new RegExp(name, 'i') }, cb);
}
//Test model可以直接使用
var Test = mongoose.model('Animal', testSchema);
Test.find('test', function (err, results) {
console.log(results);
});

虚拟属性

Mongoose 还有一个super featrue– virtual property 该属性是直接设置在Schema上的. 但是,需要注意的是,VR 并不会真正的存放在db中. 他只是一个提取数据的方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//schema基本内容
var personSchema = new Schema({
name: {
first: String,
last: String
}
});

// 生成Model
var Person = mongoose.model('Person', personSchema);

//现在我们有个需求,即,需要将first和last结合输出.
//一种方法是,使用methods来实现
//schema 添加方法
personSchema.methods.getName = function(){
return this.first+" "+this.last;
}

// 生成一个doc
var bad = new Person({
name: { first: 'jimmy', last: 'Gay' }
});

//调用
bad.getName();

但是,像这样,仅仅这是为了获取一个属性, 实际上完全可以使用虚拟属性来实现:

1
2
3
4
5
6
//schema 添加虚拟属性
personSchema.virtual('fullName').get(function(){
return this.first+" "+this.last;
})
//调用
bad.fullName; //和上面的方法的结果是完全一致的

而且,经过测试, 使用fn实现的返回,比VR 要慢几十倍. 一下是测试结果:

1
2
3
4
5
6
7
8
9
10
console.time(1);
bad.getName();
console.timeEnd(1);
console.time(2);
bad.fullName;
console.timeEnd(2);

//结果为:
1: 4.323ms; //method
2: 0.253ms // VR

最后再补充一下,Schema中初始化的相关参数.
Schema参数 在 new Schema([options]) 中,我们需要设置一些相关的参数:

safe: 用来设置安全模式. 实际上,就是定义入库时数据的写入限制. 比如写入时限等:

1
2
3
4
5
6
7
//使用安全模式. 表示在写入操作时,如果发生错误,也需要返回信息.
var safe = true;
new Schema({ .. }, { safe: safe });

// 自定义安全模式. w为写入的大小范围. wtimeout设置写入时限. 如果超出10s则返回error
var safe = { w: "majority", wtimeout: 10000 };
new Schema({ .. }, { safe: safe });

toObject: 用来表示在提取数据的时候, 把documents 内容转化为Object内容输出. 一般而言只需要设置getters为true即可:

1
2
3
4
5
6
7
8
r schema = new Schema({ name: String });
schema.path('name').get(function (v) {
return v + ' is my name';
});
schema.set('toObject', { getters: true });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }

toJSON: 该是和toObject一样的使用. 通常用来把 documents 转化为Object. 但是, 需要显示使用toJSON()方法:

1
2
3
4
5
6
7
8
9
10
11
var schema = new Schema({ name: String });
schema.path('name').get(function (v) {
return v + ' is my name';
});
schema.set('toJSON', { getters: true, virtuals: false });
var M = mongoose.model('Person', schema);
var m = new M({ name: 'Max Headroom' });
console.log(m.toObject()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom' }
console.log(m.toJSON()); // { _id: 504e0cd7dd992d9be2f20b6f, name: 'Max Headroom is my name' }
// since we know toJSON is called whenever a js object is stringified:
console.log(JSON.stringify(m)); // { "_id": "504e0cd7dd992d9be2f20b6f", "name": "Max Headroom is my name" }

model 的子文档操作

本来mongodb是没有关系的. 但是, mongoose提供了children字段. 让我们能够轻松的在表间建立关系. 现在,我们来创建一个子域:

1
2
3
4
5
6
7
8
9
10
var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
children: [childSchema] //指明sub-doc的schema
});
//在创建中指明doc
var Parent = mongoose.model('Parent', parentSchema);
var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
parent.children[0].name = 'Matthew';
parent.save(callback);

现在, 我们就已经创建了3个table. 一个parent 包含了 两个child 另外,如果我们想要查询指定的doc。 则可以使用 id()方法:

1
var doc = parent.children.id(id);

子文档的CRUD, 实际上就是数组的操作, 比如push,unshift,remove,pop,shift等:

1
parent.children.push({ name: 'Liesl' });

mongoose还给移除提供了另外一个方法–remove:

1
var doc = parent.children.id(id).remove();

如果你忘记添加子文档的话,可以在外围添加, 但是字段必须在Schema中指定:

1
var newdoc = parent.children.create({ name: 'Aaron' });

document的CRUD操作

document的创建

document 的创建 关于document的创建,有两种方法, 一种是使用document实例创建,另外一种是使用Model类创建:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var Tank = mongoose.model('Tank', yourSchema);

var small = new Tank({ size: 'small' });
//使用实例创建
small.save(function (err) {
if (err) return handleError(err);
// saved!
})

//使用Model类创建
Tank.create({ size: 'small' }, function (err, small) {
if (err) return handleError(err);
// saved!
})

document的查询

Mongoose查找文档很容易,它支持MongoDB的丰富的查询语法。 可以使用每个models find,findById,findOne或where 等静态方法进行查找文档。事实上,在mongoose中,query数据 提供了两种方式:

callback: 使用回调函数, 即query会立即执行,然后返回到回调函数中,其中‘name occupation’为设置查询选项:

1
2
3
4
Person.findOne({ 'name.last': 'Ghost' }, 'name occupation', function (err, person) {
if (err) return handleError(err);
// get data
})

query: 使用查询方法,返回的是一个Query对象. 该对象是一个Promise, 所以可以使用 chain 进行调用.最后必须使用exec(cb)传入回调进行处理. cb 是一个套路, 第一个参数永远是err. 第二个就是返回的数据。

1
Tank.find({ size: 'small' }).where('createdDate').gt(oneYearAgo).exec(callback);

以下两种等价写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// With a JSON doc
Person.
find({
occupation: /host/,
'name.last': 'Ghost',
age: { $gt: 17, $lt: 66 },
likes: { $in: ['vaporizing', 'talking'] }
}).
limit(10).
sort({ occupation: -1 }).
select({ name: 1, occupation: 1 }).
exec(callback);

// Using query builder
Person.
find({ occupation: /host/ }).
where('name.last').equals('Ghost').
where('age').gt(17).lt(66).
where('likes').in(['vaporizing', 'talking']).
limit(10).
sort('-occupation').
select('name occupation').
exec(callback);

Query Helpers:你能够添加 query helper functions,跟定义在Schema实例方法一样,但是返回query对象作为mongoose queries使用(说句白了就是封装mongoose查询方法). Query helper methods 使你能够扩展mongoose’s chainable query builder API:

1
2
3
4
5
6
7
8
animalSchema.query.byName = function(name) {
return this.find({ name: new RegExp(name, 'i') });
};

var Animal = mongoose.model('Animal', animalSchema);
Animal.find().byName('fido').exec(function(err, animals) {
console.log(animals);
});

上面4个API, 3个使用方式都是一样的, 另外一个不同的是where. 他一样是用来进行query. 只是,写法和find系列略有不同:

1
2
3
User.find({age: {$gte: 21, $lte: 65}}, callback);
//等价于:
User.where('age').gte(21).lte(65).exec(callback);

另外还有一些游标集合的处理方法: 常用的就3个, limit,skip,sort,跟原生mongoDB提供的一样:

1
2
3
4
5
6
7
8
//limit:用来获取限定长度的内容.
query.limit(20); //只返回前20个内容

//skip: 返回,跳过指定doc后的值.
query.skip(2);

//sort: 用来设置根据指定字段排序. 可以设置为1:升序, -1:降序.
query.sort({name:1,age:-1});

document删除

reomve操作仅在通过回调时执行。 要强制执行没有回调,您必须先调用remove(),然后使用exec()方法执行它。

我们可以在document上执行remove方法也可以在Model上。

1
2
3
4
5
Model.find().remove({ name: 'Anne Murray' }, callback)
Model.remove({ name: 'Anne Murray' }, callback)
//没有添加回调情况
Model.find().remove({ name: 'Anne Murray' }).remove(callback)
Model.remove({ name: 'Anne Murray' }).exce(callback)

document更新

使用Model.update([(conditions, doc, [options], [callback])]
不返回更新对象到应用程序。如果要更新数据库中的单个文档并将其返回到应用程序,请改用findOneAndUpdate。

参数说明:

  • conditions: 就是query. 通过query获取到指定doc
  • doc: 就是用来替换doc内容的值.
  • options:
    • safe (boolean) 是否开启安全模式 (default for true)
    • upsert (boolean) 如果没有匹配到内容,是否自动创建 ( default for false)
    • multi (boolean) 如果有多个doc,匹配到,是否一起更改 ( default for false)
    • strict (boolean) 使用严格模式(default for false)
    • overwrite (boolean) 匹配到指定doc,是否覆盖 (default for false)
    • runValidators (boolean): 表示是否用来启用验证. 实际上,你首先需要写一个验证. 关于如果书写,验证大家可以参考下文, validate篇(default for false)

new(使用findOneAndUpdate时才有参数):bool - 如果为true,则返回修改后的文档而不是原始文件。 默认为false。

1
2
3
4
5
Model.update({age:18}, { $set: { name: 'jason borne' }}, {multi:true}, function (err, raw) {
if (err) return handleError(err);
console.log('raw 就是mongodb返回的更改状态的falg ', raw);
//比如: { ok: 1, nModified: 2, n: 2 }
});。

其中的$set是,用来指明更新的字段。

中间件

mongoose里的中间件,有两个, 一个是pre, 一个是post:

  • pre: 在指定方法执行之前绑定。 中间件的状态分为 parallel 和 series
  • post: 相当于事件监听的绑定

这里需要说明一下, 中间件一般仅仅只能限于在几个方法中使用. (但感觉就已经是全部了):

  • doc 方法上: init,validate,save,remove;
  • model方法上: count,find,findOne,findOneAndRemove,findOneAndUpdate,update

pre

我们来看一下 pre 中间件是如何绑定的:

串行:

1
2
3
4
5
var schema = new Schema(..);
schema.pre('save', function(next) {
// do stuff
next(); //执行完毕,执行下一中间件
});

并行:

1
2
3
4
5
6
7
8
9
var schema = new Schema(..);

// 设置第二参数为true,意味这是一个并行中间件
// as the second parameter if you want to use parallel middleware.
schema.pre('save', true, function(next, done) {
// calling next kicks off the next middleware in parallel
next();
setTimeout(done, 100);
});

post

post会在指定事件后触发,就像事件监听器一样,post钩子没什么控制流程,即它是异步的。

1
2
3
4
schema.post('save', function(doc) {
//在save完成后 触发.
console.log('%s has been saved', doc._id);
});

当save方法调用时, 便会触发post绑定的save事件。假如你绑定了多个post。 也可以需要指定一下中间件顺序:

1
2
3
4
5
6
7
8
// Takes 2 parameters: this is an asynchronous post hook
schema.post('save', function(doc, next) {
setTimeout(function() {
console.log('post1');
// Kick off the second post hook
next();
}, 10);
});

Validation验证器

验证器在SchemaType中定义。

Validation 是一种中间件,Mongoose 触发 validation 同 a pre(‘save’)钩子一样 。你能够手动触发 validation 通过doc.validate(callback) or doc.validateSync()。

1
2
3
4
5
6
7
8
9
10
11
12
cat.save(function(error) {
//自动执行,validation
});

//手动触发 validatio
//上面已经设置好user的字段内容.
user.validate(function(error) {
//error 就是验证不通过返回的错误信息
assert.equal(error.errors['phone'].message,
'555.0123 is not a valid phone number!');
});
});

内置验证器

Mongoose 有一些列内置验证器:

  • 所有的SchemaTypes都有required验证器
  • min,max: 用来给Number类型的数据设置限制
1
2
3
4
5
6
7
var breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Too few eggs'],
max: 12
}
});
  • enum,match,maxlength,minlength: 这些验证是给string类型的. enum 就是枚举,表示该属性值,只能出席那那些. match是用来匹配正则表达式的. maxlength&minlength 显示字符串的长度。
1
2
3
4
5
6
7
8
9
10
11
12
new Schema({
drink: {
type: String,
enum: ['Coffee', 'Tea']
},
food:{
type: String,
match:/^a/,
maxlength:12,
minlength:6
}
})

自定义验证器

如果内置验证器不够,您可以定义自定义验证器以满足您的需要:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 创建验证器
function validator (val) {
return val == 'something';
}
new Schema({ name: { type: String, validate: validator }});

// 附带自定义错误信息

var custom = [validator, 'Uh oh, {PATH} does not equal "something".']
new Schema({ name: { type: String, validate: custom }});

//添加多验证器

var many = [
{ validator: validator, msg: 'uh oh' }
, { validator: anotherValidator, msg: 'failed' }
]
new Schema({ name: { type: String, validate: many }});

// 直接通过SchemaType.validate方法定义验证器:

var schema = new Schema({ name: 'string' });
schema.path('name').validate(validator, 'validation of `{PATH}` failed with value `{VALUE}`');

验证错误对象

验证失败后返回的错误包含一个包含实际ValidatorError对象的错误对象。 每个ValidatorError都有kind,path,value和message属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var toySchema = new Schema({
color: String,
name: String
});

var Toy = db.model('Toy', toySchema);

var validator = function (value) {
return /blue|green|white|red|orange|periwinkle/i.test(value);
};
Toy.schema.path('color').validate(validator,
'Color `{VALUE}` not valid', 'Invalid color');

var toy = new Toy({ color: 'grease'});

toy.save(function (err) {
// err is our ValidationError object
// err.errors.color is a ValidatorError object
assert.equal(err.errors.color.message, 'Color `grease` not valid');
assert.equal(err.errors.color.kind, 'Invalid color');
assert.equal(err.errors.color.path, 'color');
assert.equal(err.errors.color.value, 'grease');
assert.equal(err.name, 'ValidationError');
});

更新验证器

在Model.update那一节有个参数–runValidators. 还没有详细说. 这里, 展开一下. 实际上, validate一般只会应用在save上, 如果你想在update使用的话, 需要额外的trick,而runValidators就是这个trick。

Mongoose 还支持 update()和findOneAndUpdate()操作的验证。 在 Mongoose 4.x 中,更新验证器默认关闭 - 您需要指定 runValidators 选项。

1
2
3
4
var opts = { runValidators: true };
Test.update({}, update, opts, function(error) { //额外开启runValidators的验证
// There will never be a validation error here
});

population

mongoDB 本来就是一门非关系型数据库。 但有时候,我们又需要联合其他的table进行数据查找。 mongoose提供的 population. 用来连接多表数据查询. 一般而言, 我们只要提供某一个 collection的 _id , 就可以实现完美的联合查询. population 用到的关键字是: ref 用来指明外联的数据库的名字. 一般,我们需要在 schema 中就定义好.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var mongoose = require('mongoose')
, Schema = mongoose.Schema

var personSchema = Schema({
_id : Number,
name : String,
age : Number,
stories : [{ type: Schema.Types.ObjectId, ref: 'Story' }]
});

var storySchema = Schema({
_creator : { type: Number, ref: 'Person' },
title : String,
fans : [{ type: Number, ref: 'Person' }]
});

var Story = mongoose.model('Story', storySchema);
var Person = mongoose.model('Person', personSchema);

注意:ObjectId,Number, String, 和 Buffer 都可以作为 refs 使用。

使用populate query方法进行关联

1
2
3
4
5
6
7
8
Story
.findOne({ title: 'Once upon a timex.' })
.populate('_creator')
.exec(function (err, story) {
if (err) return handleError(err);
console.log('The creator is %s', story._creator.name);
// prints "The creator is Aaron"
});

完整的增删改查小例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// mongoose 链接
var mongoose = require('mongoose');
var db = mongoose.createConnection('mongodb://127.0.0.1:27017/mongooseTest');

// 连接错误
db.on('error', function(error) {
console.log(error);
});

// Schema 结构
var mongooseSchema = new mongoose.Schema({
username : {type : String, default : '匿名用户'},
title : {type : String},
content : {type : String},
time : {type : Date, default: Date.now},
age : {type : Number}
});

// 添加 mongoose 实例方法
mongooseSchema.methods.findbyusername = function(username, callback) {
return this.model('mongoose').find({username: username}, callback);
}

// 添加 mongoose 静态方法,静态方法在Model层就能使用
mongooseSchema.statics.findbytitle = function(title, callback) {
return this.model('mongoose').find({title: title}, callback);
}

// model
var mongooseModel = db.model('mongoose', mongooseSchema);

// 增加记录 基于 entity 操作
var doc = {username : 'emtity_demo_username', title : 'emtity_demo_title', content : 'emtity_demo_content'};
var mongooseEntity = new mongooseModel(doc);
mongooseEntity.save(function(error) {
if(error) {
console.log(error);
} else {
console.log('saved OK!');
}
// 关闭数据库链接
//db.close(); mongoose不需要显示关闭数据库
});

// 增加记录 基于model操作
var doc = {username : 'model_demo_username', title : 'model_demo_title', content : 'model_demo_content'};
mongooseModel.create(doc, function(error){
if(error) {
console.log(error);
} else {
console.log('save ok');
}
});

// 修改记录
mongooseModel.update(conditions, update, options, callback);
var conditions = {username : 'model_demo_username'};
var update = {$set : {age : 27, title : 'model_demo_title_update'}};
var options = {upsert : true};
mongooseModel.update(conditions, update, options, function(error){
if(error) {
console.log(error);
} else {
console.log('update ok!');
}
});

// 查询
// 基于实例方法的查询
var mongooseEntity = new mongooseModel({});
mongooseEntity.findbyusername('model_demo_username', function(error, result){
if(error) {
console.log(error);
} else {
console.log(result);
}
});

// 基于静态方法的查询
mongooseModel.findbytitle('emtity_demo_title', function(error, result){
if(error) {
console.log(error);
} else {
console.log(result);
}
});

// mongoose find
var criteria = {title : 'emtity_demo_title'}; // 查询条件
var fields = {title : 1, content : 1, time : 1}; // 待返回的字段
var options = {};
mongooseModel.find(criteria, fields, options, function(error, result){
if(error) {
console.log(error);
} else {
console.log(result);
}
});

// 删除记录
var conditions = {username: 'emtity_demo_username'};
mongooseModel.remove(conditions, function(error){
if(error) {
console.log(error);
} else {
console.log('delete ok!');
}
});

完~


参考链接:Mongoose初使用总结
最后增删改查例子引用:node.js下mongoose简单操作实例